import os
import xlrd
import PySimpleGUI as sg
from utils.settings import OUTPUT_PATH
from utils.gui_kit import _create_window
from utils.enclosing import counter_format
from utils.generator import schedules_couter
from utils.decorator import progress_bar


def sheet_names(file_path: str) -> list:
    """获取Excel文件包含的所有工作表名称

    Args:
        file_path (str): excel文件的路径

    Returns:
        list: 所有的sheet名称
    """
    try:
        workbook = xlrd.open_workbook(file_path)
        return workbook.sheet_names()

    except Exception as e:
        print('读取排考Excel文件失败。{0}[详细]{1}'.format('\n', e))


def exam_schedules(fileName: str, sheetName: str) -> list:
    """根据排考文件，提取【场次】和【考室】两级目录名称

    Args:
        fileName (str): 文件名
        sheetName (str): sheet名字

    Returns:
        list: 包含场次、考试字典的列表，[{},]
        [{'场次': '第1场[2021-11-29]操作系统安全', '考室': '[4-201]信安2001班'},]
    """
    schedule_list = [ ]
    # 读取文件
    try:
        workbook = xlrd.open_workbook(fileName)
        # 根据sheet索引或者名称获取sheet内容,sheet索引从0开始
        # sheet_data = workbook.sheet_by_index(0)
        sheet_data = workbook.sheet_by_name(sheetName)

        for row in range(1, sheet_data.nrows):
            schedule = {"场次": "", "考室": ""}
            # 2/日期
            exam_date = xlrd.xldate_as_datetime(sheet_data.cell_value(row, 2),0)
            exam_date = exam_date.strftime("%Y-%m-%d")
            # 1/场次 4/考试科目名称
            # 第1场[2019-12-30]路由技术
            schedule["场次"] = "{0}[{1}]{2}".format(
                sheet_data.cell_value(row, 1),
                exam_date,
                sheet_data.cell_value(row, 4)
            )
            # 5/考场号 7/参考班级
            # [4-101]计网1801班
            schedule["考室"] = "[{0}]{1}".format(
                sheet_data.cell_value(row, 5),
                sheet_data.cell_value(row, 7)
            )

            schedule_list.append(schedule)

    except Exception as e:
        print('排考数据格式不符合规范。{}[详细]{}'.format('\n', e))

    else:
        print('读取排考数据{}条。'.format(len(schedule_list)))

    finally:
        return schedule_list


def create_folder(par_folder: str, sub_folder: str, output_path: str = OUTPUT_PATH) -> None:
    """在指定的文件夹下创建父/子目录

    Args:
        par_folder (str): 父文件夹名称/dict["场次"]
        sub_folder (str): 子文件夹名称/dict["考室"]
        output_path (str): 默认值参数，文件夹的存放路径
    """
    # parent dir
    parent_dir = os.path.join(output_path, par_folder)
    if not os.path.isdir(parent_dir):
        os.mkdir(parent_dir)

    # full path
    sub_dir = os.path.join(parent_dir, sub_folder)
    if not os.path.isdir(sub_dir):
        os.mkdir(sub_dir)


if __name__ == "__main__":
    window = _create_window()
    # Event Loop to process "events" and get the "values"
    while True:
        event, values = window.read()
        file_path = values['-FILE-']
        sheet_name = values['-SHEET-']

        # 选择了排考文件
        if event == '-FILE-' and len(file_path) > 0:
            # 初始化Combo/Listbox
            window['-SHEET-'].update(value='-请选择-', values=['-请选择-'])
            window['-DIREC-'].update(values=[])
            # 获取Excel文件的所有sheet名称
            sheets = sheet_names(file_path)
            # 如果正确读取了合规的Excel文件，用sheet名称更新下拉列表框
            if sheets != None:
                sheets.insert(0, '-请选择-')
                window['-SHEET-'].update(value=sheets[0], values=sheets)
            
            continue
        
        # 选择了sheet，同步更新combo组合框数据
        if event == "-SHEET-" and sheet_name != '-请选择-':
            # 读取排考的【场次】和【考室】数据，二者构成父子目录关系
            # [{'场次': '第1场[2021-11-29]操作系统安全', '考室': '[4-201]信安2001班'},]
            schedule_list = exam_schedules(file_path, sheet_name)
            
            # 在Listbox中显示文件夹信息
            # 方式1 - 简单拼接父子目录
            # window['-DIREC-'].update(
            #     list(
            #         map(
            #             lambda d:d['场次']+' / '+d['考室'],
            #             schedule_list
            #         )
            #     )
            # )

            # 方式2 - 通过生成器实现计数拼接
            # counter = schedules_couter(len(schedule_list))
            # window['-DIREC-'].update(
            #     list(
            #         map(
            #             lambda d:'({0:03}) {1} / {2}'.format(
            #                 next(counter),
            #                 d['场次'],
            #                 d['考室']
            #             ),
            #             schedule_list
            #         )
            #     )
            # )

            # 方式3 - 通过闭包实现计数拼接
            func_count_format = counter_format()
            window['-DIREC-'].update(
                list(
                    map(func_count_format, schedule_list)
                )
            )

            continue

        # 批量创建文件夹
        if event == '确定':
            # 判断是否选择了Excel文件
            if (len(file_path) == 0):
                sg.popup('请先选择排考文件！',
                         title='错误',
                         font=("DengXian", 14),
                         line_width=24)
            # 判断是否选择了sheet表
            elif sheet_name == '-请选择-':
                sg.popup('请选择Sheet工作表！',
                         title='错误',
                         font=("DengXian", 14),
                         line_width=24)
            else:
                # 正确读取了排考数据，批量创建文件夹
                # 获取总排考数据条数max_item
                if (max_item := len(schedule_list)) > 0:
                    # 方式1 — 直接在主程序中迭代调用函数创建
                    # enumerate( )函数返回可迭代对象元素及其索引值
                    # for i, schedule in enumerate(schedule_list):
                    #     # create_folder(schedules[i]['场次'], schedules[i]['考室'])
                    #     create_folder(schedule['场次'], schedule['考室'])
                    
                    # 方式2 — 采用装饰器改造，增加进度条
                    @progress_bar(max_item)
                    def process_create_decorate(exam_num: str, exam_room: str):
                        create_folder(exam_num, exam_room)
                    # 调用函数
                    for schedule in schedule_list:
                        process_create_decorate(schedule['场次'], schedule['考室'])
                    
            continue

        # 更改Window窗口主题
        if values['-THEMES-'] != None:
            window.close()
            sg.theme(values['-THEMES-'])
            window = _create_window()
            continue

        # 关闭窗口
        if event in (None,
                     sg.WIN_CLOSED,
                     sg.WINDOW_CLOSE_ATTEMPTED_EVENT,
                     '关闭') and \
            sg.popup_yes_no('你确定要退出程序吗?',
                            title='提示',
                            font=("DengXian", 14)) == 'Yes':
            break

    # 关闭程序
    window.close()